//go:build linux
// +build linux

package iouring_syscall

import (
	"syscall"
	"unsafe"
)

// IOUringSQE ...
type IOUringSQE struct {
	// opcode   uint8  // type of operation for this sqe
	// flags    uint8  // IOSQE_ flags
	// ioprio   uint16 // ioprio for the request
	// fd       int32  // file descriptor to do IO on
	// opFlags  uint32
	// len      uint32 // buffer size or number of iovecs
	// userdata uint64 // data to be passed back at completion time
	// addr     uint64
	// seqUnion1
	// // seqUnion2
	// seqUnion3
	// seqUnion4

	opcode   uint8
	flags    uint8
	ioprio   uint16
	fd       int32
	offset   uint64
	addr     uint64
	len      uint32
	opFlags  uint32
	userdata uint64

	bufIndexOrGroup uint16
	personality     uint16
	spliceFdIn      int32
	extra           [2]uint64
}

// union
type seqUnion1 struct {
	off  uint64
	add2 uint64
}

// union
type seqUnion2 struct {
	addr          uint64
	splice_off_in uint64
}

// union
type seqUnion3 struct {
	// __kernel_rwf_t	rw_flags
	fsyncFlags       uint32
	pollEvents       uint16 /* compatibility */
	poll32_events    uint32 /* word-reversed for BE */
	sync_range_flags uint32
	msg_flags        uint32
	timeout_flags    uint32
	accept_flags     uint32
	cancel_flags     uint32
	open_flags       uint32
	statx_flags      uint32
	fadvise_advice   uint32
	splice_flags     uint32
	rename_flags     uint32
	unlink_flags     uint32
}

// union
type seqUnion4 struct {
	buf_index    uint16
	buf_group    uint16
	personality  uint16
	splice_fd_in int32
	pad2         [3]uint64
}

// SetData
func (sqe *IOUringSQE) SetData(data uint64) {
	sqe.userdata = data
}

// SetFlags ...
func (sqe *IOUringSQE) SetFlags(flags uint8) {
	sqe.flags = flags
}

// ioUringPrepRW
func (sqe *IOUringSQE) ioUringPrepRW(op uint8, fd int, addr unsafe.Pointer, len uint32, offset int64) {
	sqe.opcode = op
	sqe.fd = int32(fd)
	sqe.offset = uint64(offset)
	sqe.addr = uint64((uintptr(addr)))
	sqe.len = len
	sqe.flags = uint8(0)
}

// PrepReadv ...
func (sqe *IOUringSQE) PrepReadv(fd int, iovecs []syscall.Iovec, n uint32, offset int64) {
	bp := unsafe.Pointer(&iovecs[0])
	sqe.ioUringPrepRW(IORING_OP_READV, fd, bp, n, offset)
}

// PrepRead ...
func (sqe *IOUringSQE) PrepRead(fd int, b []byte, offset int64) {
	bp := unsafe.Pointer(&b[0])
	sqe.ioUringPrepRW(IORING_OP_READ, fd, bp, uint32(len(b)), offset)
}

// PrepReadFixed ...
func (sqe *IOUringSQE) PrepReadFixed(fd int, buf unsafe.Pointer, nbytes uint32, offset int64) {
	sqe.ioUringPrepRW(IORING_OP_READ_FIXED, fd, buf, nbytes, offset)
}

// PrepWritev ...
func (sqe *IOUringSQE) PrepWritev(fd int, iovecs []syscall.Iovec, n uint32, offset int64) {
	bp := unsafe.Pointer(&iovecs[0])
	sqe.ioUringPrepRW(IORING_OP_WRITEV, fd, bp, n, offset)
}

// PrepWrite ...
func (sqe *IOUringSQE) PrepWrite(fd int, b []byte, offset int64) {
	bp := unsafe.Pointer(&b[0])
	sqe.ioUringPrepRW(IORING_OP_WRITE, fd, bp, uint32(len(b)), offset)
}

// PrepWriteFixed ...
func (sqe *IOUringSQE) PrepWriteFixed(fd int, buf unsafe.Pointer, nbytes uint32, offset int64) {
	sqe.ioUringPrepRW(IORING_OP_WRITE_FIXED, fd, buf, nbytes, offset)
}

// PrepPollAdd ...
func (sqe *IOUringSQE) PrepPollAdd(fd int, pollMask uint) {
	sqe.opcode = IORING_OP_POLL_ADD
	sqe.fd = int32(fd)
	// sqe.pollEvents = uint16(pollMask)
}

// PrepPollRemove ...
func (sqe *IOUringSQE) PrepPollRemove(fd int, userData unsafe.Pointer) {
	sqe.opcode = IORING_OP_POLL_REMOVE
	sqe.addr = uint64(uintptr(userData))
}

// PrepPollFsync ...
func (sqe *IOUringSQE) PrepPollFsync(fd int, fsyncFlags uint) {
	sqe.opcode = IORING_OP_FSYNC
	sqe.fd = int32(fd)
	// sqe.fsyncFlags = uint32(fsyncFlags)
}

// PrepPollNop ...
func (sqe *IOUringSQE) PrepPollNop(fd int) {
	sqe.opcode = IORING_OP_NOP
}

// PrepConnect ...
func (sqe *IOUringSQE) PrepConnect(fd int, addr unsafe.Pointer, addrlen int64) {
	sqe.ioUringPrepRW(IORING_OP_CONNECT, fd, addr, 0, addrlen)
}

// PrepAccept ...
func (sqe *IOUringSQE) PrepAccept(fd int, addr unsafe.Pointer, addrlen int64, flags uint8) {
	sqe.ioUringPrepRW(IORING_OP_ACCEPT, fd, addr, 0, addrlen)
	sqe.flags = flags
}

// PrepSend ...
func (sqe *IOUringSQE) PrepSend(fd int, bs []byte, l int, flags uint8) {
	bp := unsafe.Pointer(&bs[0])
	sqe.ioUringPrepRW(IORING_OP_SEND, fd, bp, uint32(len(bs)), 0)
	sqe.flags = flags
}

// PrepRecv ...
func (sqe *IOUringSQE) PrepRecv(fd int, bs []byte, l int, flags uint8) {
	bp := unsafe.Pointer(&bs[0])
	sqe.ioUringPrepRW(IORING_OP_RECV, fd, bp, uint32(len(bs)), 0)
	sqe.flags = flags
}
